package util;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.hadoop.io.Writable;

public class DiffMessage2<T1 extends Parsable<T1>, T2 extends Parsable<T2>>
		implements Writable {

	//private static final Log LOG = LogFactory.getLog(DiffMessage2.class);
	public final static String MsgSpt = ":";

	private Pair<T1, T2> bodyObj;
	private String bodyText; // a:b:cls

	private Class<? extends Parsable> clsT1;
	private Class<? extends Parsable> clsT2;
	private long msgId;

	public DiffMessage2() {
		msgId = -1;
		bodyText = "";
	}

	public DiffMessage2(long id, String ms) {
		msgId = id;
		bodyText = ms;
	}

	public DiffMessage2(long id, T1 t1, T2 t2) {
		msgId = id;
		bodyText = t1.toString() + MsgSpt + t2.toString();
		clsT1 = t1.getClass();
		clsT2 = t2.getClass();
		bodyObj = new Pair<T1, T2> (t1,t2);
	}

	public DiffMessage2(String idAndMsg,  Class<? extends Parsable> cls1, Class<? extends Parsable> cls2) {
		Pair<Long, Pair<T1, T2>> pmg;
		try {
			clsT1 = cls1;
			clsT2 = cls2;
			pmg = parse(idAndMsg);
			msgId = pmg.getFirst();
			
			bodyText = pmg.getSecond().getFirst() + MsgSpt + pmg.getSecond().getFirst();
		} catch (NoSuchMethodException | SecurityException
				| ClassNotFoundException | InstantiationException
				| IllegalAccessException | IllegalArgumentException
				| InvocationTargetException e) {
			e.printStackTrace();
		}
	
	}
	
	public DiffMessage2(Class<? extends Parsable> cls1,
			Class<? extends Parsable> cls2) {
		
		clsT1 = cls1;
		clsT2 = cls2;
		msgId = -1;
		bodyText = null;
		bodyObj= null;
	}
	

	public String getMsg() {
		return bodyText;
	}
	
	public long getMsgId() {
		return msgId;
	}

	public Pair<Long, Pair<T1, T2>> parse(String msg) throws NoSuchMethodException,
			SecurityException, ClassNotFoundException, InstantiationException,
			IllegalAccessException, IllegalArgumentException,
			InvocationTargetException {
		if ((msg != null) && (!msg.isEmpty())) {
			String[] array = msg.split(MsgSpt);
			// System.out.println("*****DiffMessage DEBUG Start*****");
			Object objT1 = clsT1.newInstance();
			Object objT2 = clsT2.newInstance();

			Method _parse1 = clsT1.getDeclaredMethod("parse",
					new Class[] { String.class });
			Method _parse2 = clsT2.getDeclaredMethod("parse",
					new Class[] { String.class });

			if (_parse1 == null || _parse2 == null) {
				System.out.println("[PRI]ParameterizedType1:"
						+ clsT1.getCanonicalName());
				System.out.println("[PRI]ParameterizedType2:"
						+ clsT2.getCanonicalName());
				return null;
			}

			long key = Long.parseLong(array[0]);
			T1 v1 = (T1) _parse1.invoke(objT1, new Object[] { array[1] });
			T2 v2 = (T2) _parse2.invoke(objT2, new Object[] { array[2] });

		//	System.out.println("parse DiffMessage2 OK ");

			Pair<T1, T2> vp = new Pair<T1, T2>(v1, v2);
			return new Pair<Long , Pair<T1, T2>>(key,vp);
		}

		return null;
	}

	@Override
	public void readFields(DataInput in) throws IOException {
		String[] msg = in.readUTF().split(MsgSpt);
		msgId = Long.parseLong(msg[0]);
		bodyText = msg[1];
	}

	public void setMsg(String ms) {
		bodyText = ms;
	}

	public void setMsgId(long id) {
		msgId = id;
	}

	@Override
	public String toString(){
		return msgId + MsgSpt +bodyText;
		
	}

	@Override
	public void write(DataOutput out) throws IOException {
		//out.writeLong(msgId);
		out.writeUTF(this.toString());
	}

}